package com.magic.cd.util;

import java.lang.reflect.Field;
import java.security.MessageDigest;
import java.util.Arrays;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;

import com.magic.cd.entry.ReceiveSignVO;

public class SignUtils {
	
    private static char[] DIGIT = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'};
	
    /**
     * 验证签名,根据开发者文档案例书写
     * @param 	sign	待验证对象
     * @return 	boolean		
     */
    public static boolean checkSignature(ReceiveSignVO sign){
    	StringBuffer buffer = new StringBuffer();
        String[] array = new String[]{Const.APP_TOKEN, sign.getTimestamp(), sign.getNonce()};
        
        //1.将 token,timestamp,nonce按字典排序
        Arrays.sort(array);
        
        //2.按新顺序拼接成待认证字符串
        for (String each : array)  buffer.append(each);

        MessageDigest md = null;
        String tmpStr = null;
        try {
            md = MessageDigest.getInstance("SHA-1");
            
            //3.将待认证字符串进行SHA-1加密
            byte[] digest = md.digest(buffer.toString().getBytes());
            tmpStr = byteToStr(digest);
        } catch (Exception e) {
            //TODO  
        } 
        //4.将SHA-1加密后的字符串可与signature对比,验证请求来自于微信
        return tmpStr==null?false:tmpStr.equals(sign.getSignature().toUpperCase());
    }
    
    /**
     * 将字节数组转换为十六进制字符串,根据开发者文档案例书写
     * @param   digest	 待转换字节数组
     * @return	String
     */
    private static String byteToStr(byte[] digest) {
    	StringBuffer buffer = new StringBuffer();
        for (byte bt : digest)  buffer.append(byteToHexStr(bt));
        return buffer.toString();
    }
    
    /**
     * 将字节转换为十六进制字符串,根据开发者文档案例书写
     * @param 	bt   待转换字节
     * @return  String
     */
    private static String byteToHexStr(byte bt) {
        char[] tempArr = new char[2];
        tempArr[0] = DIGIT[(bt >>> 4) & 0X0F];
        tempArr[1] = DIGIT[bt & 0X0F];
        return new String(tempArr);
    }
    
    /**
     * 将参数转换为ReceiverSignVO
     * @param	param  当前参数
     * @param	clz    需要转换的类型
     * @retun   T
     * */
    public static <T>T convert(Map<String,String[]> param,Class<T> clz){
    	T obj = null;
    	Field[] field = clz.getDeclaredFields();
    	Set<Entry<String, String[]>>  entrty = param.entrySet();
    	try {
    		obj = clz.newInstance();
			for (Entry<String, String[]> e : entrty) {
				String key = e.getKey();
				String value = e.getValue()[0];
				for (Field f : field) {
					if(f.getName().equals(key)){
						f.setAccessible(true);
						f.set(obj, value);
					}
				}
			}
		} catch (Exception ee) {
			ee.printStackTrace();
			//TODO
		}
    	return obj;
    }
}
